package com.hdmall.business.common.util;
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

public class RSACoderUtiltTest {
    //非对称密钥算法
    public static final String KEY_ALGORITHM="RSA";
    /**
     * 密钥长度，DH算法的默认密钥长度是1024
     * 密钥长度必须是64的倍数，在512到65536位之间
     * */
    private static final int KEY_SIZE=512;
//    //服务器公钥
    private static final String PUBLIC_KEY="MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKPFkKaUDh+/smPu2vpiMxjVHwLmByUwxPYrzuKEODERRPYR9eExccS2UqayMbK8UYNfbtQ+nwvQhCImVDcVsHECAwEAAQ==";
//
//    //服务器私钥
    private static final String PRIVATE_KEY="MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEAo8WQppQOH7+yY+7a+mIzGNUfAuYHJTDE9ivO4oQ4MRFE9hH14TFxxLZSprIxsrxRg19u1D6fC9CEIiZUNxWwcQIDAQABAkACwZ14oD9Im4JWGjwHQMXZYiTeeJ6gKpz2A7C8sTr84GWNLaLZYJKr7StR3i808LqMD0eTPYYBxbkWXC/BcwGRAiEA79jNQWtY8OelnxgqxUZDX3ryCXWFMMXE+LWUo9bYGjUCIQCuzSb9kSKHteDVM6nBkshwzjY+BoFwSza/KW4m1BxkzQIgMFhI9zjGErj+n1TluiHxjptfkhyIHk6e52ribSvvH0kCIGjrmNCwUcKVh9tQxD79RLR5AhPewcjOTJEXZBeIT3atAiBJFVEIllpxlVSJp5kAQlPAdlqXHvDraWYWpDHE54Gruw==";
    /**
     * 初始化服务器密钥对
     * @return Map 甲方密钥的Map
     * */
    public static Map<String,Object> initKey() throws Exception{
        //实例化密钥生成器
        KeyPairGenerator keyPairGenerator=KeyPairGenerator.getInstance(KEY_ALGORITHM);
        //初始化密钥生成器
        keyPairGenerator.initialize(KEY_SIZE);
        //生成密钥对
        KeyPair keyPair=keyPairGenerator.generateKeyPair();
        //甲方公钥
        RSAPublicKey publicKey=(RSAPublicKey) keyPair.getPublic();
        System.out.println("系数："+publicKey.getModulus()+"  加密指数："+publicKey.getPublicExponent());
        //甲方私钥
        RSAPrivateKey privateKey=(RSAPrivateKey) keyPair.getPrivate();
        System.out.println("系数："+privateKey.getModulus()+"解密指数："+privateKey.getPrivateExponent());
        //将密钥存储在map中
        Map<String,Object> keyMap=new HashMap<String,Object>();
        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);
        return keyMap;

    }
    /**
     * 私钥加密
     * @param data待加密数据
     * @param key 密钥
     * @return byte[] 加密数据
     * */
   public static byte[] encryptByPrivateKey(byte[] data,byte[] key) throws Exception{

        //取得私钥
        PKCS8EncodedKeySpec pkcs8KeySpec=new PKCS8EncodedKeySpec(key);
        KeyFactory keyFactory=KeyFactory.getInstance(KEY_ALGORITHM);
        //生成私钥
        PrivateKey privateKey=keyFactory.generatePrivate(pkcs8KeySpec);
        //数据加密
        Cipher cipher=Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);
        return cipher.doFinal(data);
    }

    /**
     * 公钥加密
     * @param data待加密数据
     * @param key 密钥
     * @return byte[] 加密数据
     * */
    public static byte[] encryptByPublicKey(byte[] data,byte[] key) throws Exception{

        //实例化密钥工厂
        KeyFactory keyFactory=KeyFactory.getInstance(KEY_ALGORITHM);
        //初始化公钥
        //密钥材料转换
        X509EncodedKeySpec x509KeySpec=new X509EncodedKeySpec(key);
        //产生公钥
        PublicKey pubKey=keyFactory.generatePublic(x509KeySpec);

        //数据加密
        Cipher cipher=Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
        return cipher.doFinal(data);
    }
    /**
     * 私钥解密
     * @param data 待解密数据
     * @param key 密钥
     * @return byte[] 解密数据
     * */
    public static byte[] decryptByPrivateKey(byte[] data,byte[] key) throws Exception{
        //取得私钥
        PKCS8EncodedKeySpec pkcs8KeySpec=new PKCS8EncodedKeySpec(key);
        KeyFactory keyFactory=KeyFactory.getInstance(KEY_ALGORITHM);
        //生成私钥
        PrivateKey privateKey=keyFactory.generatePrivate(pkcs8KeySpec);
        //数据解密
        Cipher cipher=Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        return cipher.doFinal(data);
    }

    /**
     * 公钥解密
     * @param data 待解密数据
     * @param key 密钥
     * @return byte[] 解密数据
     * */
    public static byte[] decryptByPublicKey(byte[] data,byte[] key) throws Exception{

        //实例化密钥工厂
        KeyFactory keyFactory=KeyFactory.getInstance(KEY_ALGORITHM);
        //初始化公钥
        //密钥材料转换
        X509EncodedKeySpec x509KeySpec=new X509EncodedKeySpec(key);
        //产生公钥
        PublicKey pubKey=keyFactory.generatePublic(x509KeySpec);
        //数据解密
        Cipher cipher=Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, pubKey);
        return cipher.doFinal(data);
    }

    /**
     * 取得私钥
     * @param keyMap 密钥map
     * @return byte[] 私钥
     * */
    public static byte[] getPrivateKey(Key privateKey ){
//        Key key=(Key)keyMap.get(PRIVATE_KEY);
        return privateKey.getEncoded();
    }
    /**
     * 取得公钥
     * @param keyMap 密钥map
     * @return byte[] 公钥
     * */
    public static byte[] getPublicKey(Key publicKey ){
        return publicKey.getEncoded();
    }
    //base64字符串转byte[]
    public static byte[] base64String2ByteFun(String base64Str){
        return Base64.decodeBase64(base64Str);
    }
    //byte[]转base64
    public static String byte2Base64StringFun(byte[] b){
        return Base64.encodeBase64String(b);
    }
    //客户端公钥加密
    public static String clientRequestEncryptionRSA(String data){
        byte[] publicBtKey=base64String2ByteFun(PUBLIC_KEY);
        byte[] dCode=new byte[1024];
        try {
            dCode=encryptByPublicKey(data.getBytes(),publicBtKey);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return  byte2Base64StringFun(dCode);
    }
    //服务器私钥解密
    public static String serverRequestDecryptRSA(String data){
        byte[] code=new byte[1024];;
        if(data!=null){
            code= base64String2ByteFun(data);
        }
        byte[] privateBtKey=base64String2ByteFun(PRIVATE_KEY);
        byte[] dCode=new byte[1024];
        try {
            dCode=decryptByPrivateKey(code,privateBtKey);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return  new String(dCode);
    }
    //服务器私钥加密
    public static String serverResponseEncryptionRSA(String data){
        byte[] privteBtKey=base64String2ByteFun(PRIVATE_KEY);
        byte[] dCode=new byte[1024];
        try {
            dCode=encryptByPrivateKey(data.getBytes(),privteBtKey);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return  byte2Base64StringFun(dCode);
    }
    //客户端公钥解密
    public static String clientResponseDecryptRSA(String data){
        byte[] code=new byte[1024];;
        if(data!=null){
            code= base64String2ByteFun(data);
        }
        byte[] publicBtKey=base64String2ByteFun(PUBLIC_KEY);
        byte[] dCode=new byte[1024];
        try {
            dCode=decryptByPublicKey(code,publicBtKey);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return  new String(dCode);
    }
    /**
     * 私钥解密
     *
     * @param data
     * @param privateKey
     * @return
     * @throws Exception
     */
    public static String decryptByPrivateKey(String data,
                                             RSAPrivateKey privateKey) throws Exception {
        Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        // 模长
        int key_len = privateKey.getModulus().bitLength() / 8;
        byte[] bytes = data.getBytes();
        byte[] bcd = ASCII_To_BCD(bytes, bytes.length);
        System.err.println(bcd.length);
        // 如果密文长度大于模长则要分组解密
        String ming = "";
        byte[][] arrays = splitArray(bcd, key_len);
        for (byte[] arr : arrays) {
            ming += new String(cipher.doFinal(arr));
        }
        return ming;
    }

    /**
     * ASCII码转BCD码
     *
     */
    private static byte[] ASCII_To_BCD(byte[] ascii, int asc_len) {
        byte[] bcd = new byte[asc_len / 2];
        int j = 0;
        for (int i = 0; i < (asc_len + 1) / 2; i++) {
            bcd[i] = asc_to_bcd(ascii[j++]);
            bcd[i] = (byte) (((j >= asc_len) ? 0x00 : asc_to_bcd(ascii[j++])) + (bcd[i] << 4));
        }
        return bcd;
    }

    private static byte asc_to_bcd(byte asc) {
        byte bcd;

        if ((asc >= '0') && (asc <= '9'))
            bcd = (byte) (asc - '0');
        else if ((asc >= 'A') && (asc <= 'F'))
            bcd = (byte) (asc - 'A' + 10);
        else if ((asc >= 'a') && (asc <= 'f'))
            bcd = (byte) (asc - 'a' + 10);
        else
            bcd = (byte) (asc - 48);
        return bcd;
    }

    /**
     * BCD转字符串
     */
    private static String bcd2Str(byte[] bytes) {
        char temp[] = new char[bytes.length * 2], val;

        for (int i = 0; i < bytes.length; i++) {
            val = (char) (((bytes[i] & 0xf0) >> 4) & 0x0f);
            temp[i * 2] = (char) (val > 9 ? val + 'A' - 10 : val + '0');

            val = (char) (bytes[i] & 0x0f);
            temp[i * 2 + 1] = (char) (val > 9 ? val + 'A' - 10 : val + '0');
        }
        return new String(temp);
    }

    /**
     * 拆分字符串
     */
    private static String[] splitString(String string, int len) {
        int x = string.length() / len;
        int y = string.length() % len;
        int z = 0;
        if (y != 0) {
            z = 1;
        }
        String[] strings = new String[x + z];
        String str = "";
        for (int i = 0; i < x + z; i++) {
            if (i == x + z - 1 && y != 0) {
                str = string.substring(i * len, i * len + y);
            } else {
                str = string.substring(i * len, i * len + len);
            }
            strings[i] = str;
        }
        return strings;
    }

    /**
     * 拆分数组
     */
    private static byte[][] splitArray(byte[] data, int len) {
        int x = data.length / len;
        int y = data.length % len;
        int z = 0;
        if (y != 0) {
            z = 1;
        }
        byte[][] arrays = new byte[x + z][];
        byte[] arr;
        for (int i = 0; i < x + z; i++) {
            arr = new byte[len];
            if (i == x + z - 1 && y != 0) {
                System.arraycopy(data, i * len, arr, 0, y);
            } else {
                System.arraycopy(data, i * len, arr, 0, len);
            }
            arrays[i] = arr;
        }
        return arrays;
    }
    public static void main(String[] args) {
        String response=serverResponseEncryptionRSA("返回信息8888888888888888888888");
        String r=clientResponseDecryptRSA(response);
        System.out.println(r);
        /*String msg= clientRequestEncryptionRSA("你好北京！！！");
        System.out.println(msg);
        String msg2= clientRequestDecryptRSA(msg);
        System.out.println(msg2);*/
        //初始化密钥
        //生成密钥对
        //实例化密钥生成器
        /*KeyPairGenerator keyPairGenerator= null;
        try {
            keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        //初始化密钥生成器
        keyPairGenerator.initialize(KEY_SIZE);
        //生成密钥对
        KeyPair keyPair=keyPairGenerator.generateKeyPair();
        //甲方公钥
        RSAPublicKey publicKey=(RSAPublicKey) keyPair.getPublic();
//        System.out.println("系数："+publicKey.getModulus()+"  加密指数："+publicKey.getPublicExponent());
        //甲方私钥
        RSAPrivateKey privateKey=(RSAPrivateKey) keyPair.getPrivate();
//        System.out.println("系数："+privateKey.getModulus()+"解密指数："+privateKey.getPrivateExponent());
        //将密钥存储在map中
        *//*Map<String,Object> keyMap= null;
        try {
            keyMap = RSACoder.initKey();
        } catch (Exception e) {
            e.printStackTrace();
        }*//*
        //公钥
        byte[] publicKeyBt= new byte[0];
        try {
            publicKeyBt = RSACoder.getPublicKey(publicKey);
        } catch (Exception e) {
            e.printStackTrace();
        }

        //byte[] publicKey = b;
        //私钥
        byte[] privateKeyBt=RSACoder.getPrivateKey(privateKey);

        String base64StrPrivateKey=byte2Base64StringFun(privateKeyBt);
        String base64StrPublicKey=byte2Base64StringFun(publicKeyBt);
        System.out.println("base64StrPrivateKey:"+base64StrPrivateKey);
        System.out.println("--------------------");
        System.out.println("base64StrPublicKey:"+base64StrPublicKey);*/
        /*System.out.println("公钥："+Base64.encodeBase64URLSafeString(publicKey));
        System.out.println("私钥："+Base64.encodeBase64URLSafeString(privateKey));*/
        //客户端公钥加密
        /*String data="server顶顶顶顶";
        byte[] codeYi=new byte[0];
        try {
            codeYi=encryptByPrivateKey(data.getBytes(),jiaPrivateKey);
        } catch (Exception e) {
            e.printStackTrace();
        }

//        System.out.println("server私钥加密=="+Base64.encodeBase64URLSafeString(codeYi));
        //服务器私钥解密
        byte[] codeJia=new byte[0];
        try {
            codeJia=decryptByPublicKey(codeYi,publicBt);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("客户端用公钥解密=="+new String(codeJia));*/
/*
        byte[] codeYi=new byte[0];
        try {
            codeYi=encryptByPublicKey(data.getBytes(),publicKey);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("客户端公钥加密=="+Base64.encodeBase64URLSafeString(codeYi));
        //服务器私钥解密
        byte[] codeJia=new byte[0];
        try {
            codeJia=decryptByPrivateKey(codeYi,jiaPrivateKey);
        } catch (Exception e) {
            e.printStackTrace();
        }
*/
//        System.out.println("服务器私钥解密=="+new String(codeJia));
       /* String response="HHHHHHHHHHHHHHHHH";
        //服务器公钥加密
        byte[] codeEn=new byte[0];
        try {
            codeEn=encrypt(response.getBytes(),publicKey);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("服务器公钥加密=="+Base64.encodeBase64URLSafeString(codeEn));
        byte[] codeDe=new byte[0];
        try {
            codeDe=decryptByPrivateKey(codeEn,jiaPrivateKey);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //客户端私钥解密
        System.out.println("客户端私钥解密=="+new String(codeDe));*/
    }
}
